// var $logManager = require("./LogManager");
// var $resLoader = require("./ResLoader");
// var $resUtil = require("./ResUtil");
// var r = (function () {
//     function e() {}
//     e.addClickEvent = function (e, t, o, i) {
//         if (void 0 === i) {
//             i = 500;
//         }
//         if (null == e ? void 0 : e.node) {
//             e.node.off("click");
//             e.node.on(
//                 "click",
//                 function (n) {
//                     if (i > 0) {
//                         var a = e.lastclickTime;
//                         if (a) {
//                             if (new Date().getTime() - a < i) {
//                                 return;
//                             }
//                             e.lastclickTime = new Date().getTime();
//                             t.apply(o, [n]);
//                         } else {
//                             e.lastclickTime = new Date().getTime();
//                             t.apply(o, [n]);
//                         }
//                     } else {
//                         t.apply(o, [n]);
//                     }
//                 },
//                 o
//             );
//         } else {
//             $logManager.LogMgr.error("add click event error: " + e);
//         }
//     };
//     e.rmClickEvent = function (e) {
//         if (null == e ? void 0 : e.node) {
//             e.node.off("click");
//         } else {
//             $logManager.LogMgr.error("remove click event error: " + e);
//         }
//     };
//     e.shake = function (e, t) {
//         var o = cc.tween(e);
//         var n = [
//             {
//                 position: cc.v2(t.x, t.y),
//                 duration: 0.05
//             },
//             {
//                 position: cc.v2(-t.x, -t.y),
//                 duration: 0.05
//             },
//             {
//                 position: cc.v2(t.x, t.y),
//                 duration: 0.05
//             },
//             {
//                 position: cc.v2(-t.x, -t.y),
//                 duration: 0.05
//             },
//             {
//                 position: cc.v2(0, 0),
//                 duration: 0.05
//             }
//         ];
//         o.by(0, {
//             position: cc.v3(0, 0)
//         });
//         var i = 0;
//         for (var a = n; i < a.length; i++) {
//             var r = a[i];
//             o.by(r.duration, {
//                 position: cc.v3(r.position)
//             });
//         }
//         o.start();
//     };
//     e.loadTexture = function (e, t, o) {
//         $resLoader.default.loadRes(t, o, cc.SpriteFrame).then(function (t) {
//             if (t) {
//                 e.spriteFrame = t;
//                 $resUtil.ResUtil.assignWith(t, e.node);
//             }
//         });
//     };
//     e.loadDragonBones = function (e, t, o) {
//         return new Promise(function (n, r) {
//             var c = cc.path.basename(o);
//             var s = cc.path.dirname(o);
//             var l = s + "/" + c + "_ske";
//             var u = s + "/" + c + "_tex";
//             $resLoader.default.loadRes(t, l, dragonBones.DragonBonesAsset).then(function (o) {
//                 if (o) {
//                     $resUtil.ResUtil.assignWith(o, e.node);
//                     $resLoader.default.loadRes(t, u, dragonBones.DragonBonesAtlasAsset).then(function (t) {
//                         if (t) {
//                             e.dragonAsset = o;
//                             e.dragonAtlasAsset = t;
//                             $resUtil.ResUtil.assignWith(o, e.node);
//                             n(!0);
//                         } else {
//                             r(!1);
//                         }
//                     });
//                 } else {
//                     r(!1);
//                 }
//             });
//         });
//     };
//     e.addTouchEventListener = function (e, t, o) {
//         e.on(cc.Node.EventType.TOUCH_START, t, o);
//         e.on(cc.Node.EventType.TOUCH_MOVE, t, o);
//         e.on(cc.Node.EventType.TOUCH_END, t, o);
//         e.on(cc.Node.EventType.TOUCH_CANCEL, t, o);
//     };
//     e.rmTouchEventListener = function (e) {
//         e.off(cc.Node.EventType.TOUCH_START);
//         e.off(cc.Node.EventType.TOUCH_MOVE);
//         e.off(cc.Node.EventType.TOUCH_END);
//         e.off(cc.Node.EventType.TOUCH_CANCEL);
//     };
//     e.fadeOut = function (e, t, o, n) {
//         if (void 0 === o) {
//             o = !1;
//         }
//         if (void 0 === n) {
//             n = !0;
//         }
//         cc.Tween.stopAllByTarget(e);
//         cc.tween(e)
//             .to(t, {
//                 opacity: 0
//             })
//             .call(function () {
//                 if (o) {
//                     $resUtil.ResUtil.removeFromParent(e, n);
//                 }
//             })
//             .start();
//     };
//     e.scaleTo = function (e, t) {
//         var o = t / Math.max(e.width, e.height);
//         e.scale = o;
//     };
//     return e;
// })();
// exports.default = r;

// import { LogMgr } from "./LogManager";
// import resLoader from "./ResLoader";
// import { ResUtil } from "./ResUtil";

// /**
//  * Utility class for various common operations.
//  * 建议类名: CommonUtils
//  */
// class CommonUtils {
//     constructor() { }

//     /**
//      * Adds a click event listener to a node with optional debounce time.
//      * @param e - The target object containing the node.
//      * @param t - The callback function to be executed on click.
//      * @param o - The context in which the callback function is executed.
//      * @param i - The debounce time in milliseconds (default is 500ms).
//      * 建议方法名: addClickEventListener
//      */
//     static addClickEvent(e: any, t: Function, o: any, i: number = 500): void {
//         if (e?.node) {
//             e.node.off("click");
//             e.node.on(
//                 "click",
//                 (n: any) => {
//                     if (i > 0) {
//                         const a = e.lastclickTime;
//                         if (a) {
//                             if (new Date().getTime() - a < i) {
//                                 return;
//                             }
//                             e.lastclickTime = new Date().getTime();
//                             t.apply(o, [n]);
//                         } else {
//                             e.lastclickTime = new Date().getTime();
//                             t.apply(o, [n]);
//                         }
//                     } else {
//                         t.apply(o, [n]);
//                     }
//                 },
//                 o
//             );
//         } else {
//             LogMgr.error("add click event error: " + e);
//         }
//     }

//     /**
//      * Removes a click event listener from a node.
//      * @param e - The target object containing the node.
//      * 建议方法名: removeClickEventListener
//      */
//     static rmClickEvent(e: any): void {
//         if (e?.node) {
//             e.node.off("click");
//         } else {
//             LogMgr.error("remove click event error: " + e);
//         }
//     }

//     /**
//      * Applies a shake animation to a node.
//      * @param e - The target node to apply the shake animation.
//      * @param t - The shake intensity vector.
//      * 建议方法名: applyShakeAnimation
//      */
//     static shake(e: cc.Node, t: cc.Vec2): void {
//         const o = cc.tween(e);
//         const n = [
//             { position: cc.v2(t.x, t.y), duration: 0.05 },
//             { position: cc.v2(-t.x, -t.y), duration: 0.05 },
//             { position: cc.v2(t.x, t.y), duration: 0.05 },
//             { position: cc.v2(-t.x, -t.y), duration: 0.05 },
//             { position: cc.v2(0, 0), duration: 0.05 }
//         ];
//         o.by(0, { position: cc.v3(0, 0) });
//         for (const r of n) {
//             o.by(r.duration, { position: cc.v3(r.position) });
//         }
//         o.start();
//     }

//     /**
//      * Loads a texture and assigns it to a sprite.
//      * @param e - The target sprite.
//      * @param t - The resource path.
//      * @param o - The resource type.
//      * 建议方法名: loadAndAssignTexture
//      */
//     static loadTexture(e: cc.Sprite, t: string, o: typeof cc.SpriteFrame): void {
//         resLoader.loadRes(t, t, cc.SpriteFrame).then((t: cc.SpriteFrame) => {
//             if (t) {
//                 e.spriteFrame = t;
//                 ResUtil.assignWith(t, e.node);
//             }
//         });
//     }

//     /**
//      * Loads DragonBones assets and assigns them to a node.
//      * @param e - The target node.
//      * @param t - The resource path.
//      * @param o - The DragonBones asset name.
//      * @returns A promise that resolves to true if successful, false otherwise.
//      * 建议方法名: loadAndAssignDragonBones
//      */
//     static loadDragonBones(e: any, t: string, o: string): Promise<boolean> {
//         return new Promise((n, r) => {
//             const c = cc.path.basename(o);
//             const s = cc.path.dirname(o);
//             const l = `${s}/${c}_ske`;
//             const u = `${s}/${c}_tex`;
//             resLoader.loadRes(t, l, dragonBones.DragonBonesAsset).then((o: dragonBones.DragonBonesAsset) => {
//                 if (o) {
//                     ResUtil.assignWith(o, e.node);
//                     resLoader.loadRes(t, u, dragonBones.DragonBonesAtlasAsset).then((t: dragonBones.DragonBonesAtlasAsset) => {
//                         if (t) {
//                             e.dragonAsset = o;
//                             e.dragonAtlasAsset = t;
//                             ResUtil.assignWith(o, e.node);
//                             n(true);
//                         } else {
//                             r(false);
//                         }
//                     });
//                 } else {
//                     r(false);
//                 }
//             });
//         });
//     }

//     /**
//      * Adds touch event listeners to a node.
//      * @param e - The target node.
//      * @param t - The callback function to be executed on touch events.
//      * @param o - The context in which the callback function is executed.
//      * 建议方法名: addTouchEventListeners
//      */
//     static addTouchEventListener(e: cc.Node, t: Function, o: any): void {
//         e.on(cc.Node.EventType.TOUCH_START, t, o);
//         e.on(cc.Node.EventType.TOUCH_MOVE, t, o);
//         e.on(cc.Node.EventType.TOUCH_END, t, o);
//         e.on(cc.Node.EventType.TOUCH_CANCEL, t, o);
//     }

//     /**
//      * Removes touch event listeners from a node.
//      * @param e - The target node.
//      * 建议方法名: removeTouchEventListeners
//      */
//     static rmTouchEventListener(e: cc.Node): void {
//         e.off(cc.Node.EventType.TOUCH_START);
//         e.off(cc.Node.EventType.TOUCH_MOVE);
//         e.off(cc.Node.EventType.TOUCH_END);
//         e.off(cc.Node.EventType.TOUCH_CANCEL);
//     }

//     /**
//      * Applies a fade-out animation to a node.
//      * @param e - The target node.
//      * @param t - The duration of the fade-out animation.
//      * @param o - Whether to remove the node from its parent after the animation (default is false).
//      * @param n - Whether to clean up the node after removal (default is true).
//      * 建议方法名: applyFadeOutAnimation
//      */
//     static fadeOut(e: cc.Node, t: number, o: boolean = false, n: boolean = true): void {
//         cc.Tween.stopAllByTarget(e);
//         cc.tween(e)
//             .to(t, { opacity: 0 })
//             .call(() => {
//                 if (o) {
//                     ResUtil.removeFromParent(e, n);
//                 }
//             })
//             .start();
//     }

//     /**
//      * Scales a node to fit within a given size.
//      * @param e - The target node.
//      * @param t - The target size.
//      * 建议方法名: scaleNodeToFit
//      */
//     static scaleTo(e: cc.Node, t: number): void {
//         const o = t / Math.max(e.width, e.height);
//         e.scale = o;
//     }
// }

// export default CommonUtils;

import { LogMgr } from "./LogManager";
import resLoader from "./ResLoader";
import { ResourceUtil } from "./ResUtil";

/**
 * Utility class for various common operations.
 * 建议类名: CommonUtils
 */
class CommonUtils {
    constructor() { }

    /**
     * Adds a click event listener to a node with optional debounce time.
     * @param targetObj - The target object containing the node.
     * @param callback - The callback function to be executed on click.
     * @param context - The context in which the callback function is executed.
     * @param debounceTime - The debounce time in milliseconds (default is 500ms).
     * 建议方法名: addClickEventListener
     */
    static addClickEvent(targetObj: any, callback: Function, context: any, debounceTime: number = 500): void {
        if (targetObj?.node) {
            targetObj.node.off("click");
            targetObj.node.on(
                "click",
                (event: any) => {
                    if (debounceTime > 0) {
                        const lastClickTime = targetObj.lastclickTime;
                        const currentTime = new Date().getTime();
                        if (lastClickTime && currentTime - lastClickTime < debounceTime) {
                            return;
                        }
                        targetObj.lastclickTime = currentTime;
                        callback.apply(context, [event]);
                    } else {
                        callback.apply(context, [event]);
                    }
                },
                context
            );
        } else {
            LogMgr.error("add click event error: " + targetObj);
        }
    }

    /**
     * Removes a click event listener from a node.
     * @param targetObj - The target object containing the node.
     * 建议方法名: removeClickEventListener
     */
    static rmClickEvent(targetObj: any): void {
        if (targetObj?.node) {
            targetObj.node.off("click");
        } else {
            LogMgr.error("remove click event error: " + targetObj);
        }
    }

    /**
     * Applies a shake animation to a node.
     * @param targetNode - The target node to apply the shake animation.
     * @param shakeIntensity - The shake intensity vector.
     * 建议方法名: applyShakeAnimation
     */
    static shake(targetNode: cc.Node, shakeIntensity: cc.Vec2): void {
        const tween = cc.tween(targetNode);
        const shakeSteps = [
            { position: cc.v2(shakeIntensity.x, shakeIntensity.y), duration: 0.05 },
            { position: cc.v2(-shakeIntensity.x, -shakeIntensity.y), duration: 0.05 },
            { position: cc.v2(shakeIntensity.x, shakeIntensity.y), duration: 0.05 },
            { position: cc.v2(-shakeIntensity.x, -shakeIntensity.y), duration: 0.05 },
            { position: cc.v2(0, 0), duration: 0.05 }
        ];
        tween.by(0, { position: cc.v3(0, 0) });
        for (const step of shakeSteps) {
            tween.by(step.duration, { position: cc.v3(step.position) });
        }
        tween.start();
    }

    /**
     * Loads a texture and assigns it to a sprite.
     * @param targetSprite - The target sprite.
     * @param resourcePath - The resource path.
     * @param resourceType - The resource type.
     * 建议方法名: loadAndAssignTexture
     */
    static loadTexture(targetSprite: cc.Sprite, resourcePath: string, resourceType: typeof cc.SpriteFrame): void {
        resLoader.loadRes(resourcePath, resourcePath, cc.SpriteFrame).then((spriteFrame: cc.SpriteFrame) => {
            if (spriteFrame) {
                targetSprite.spriteFrame = spriteFrame;
                ResourceUtil.assignResourceWith(spriteFrame, targetSprite.node);
            }
        });
    }

    /**
     * Loads DragonBones assets and assigns them to a node.
     * @param targetNode - The target node.
     * @param resourcePath - The resource path.
     * @param assetName - The DragonBones asset name.
     * @returns A promise that resolves to true if successful, false otherwise.
     * 建议方法名: loadAndAssignDragonBones
     */
    static loadDragonBones(targetNode: any, resourcePath: string, assetName: string): Promise<boolean> {
        return new Promise((resolve, reject) => {
            const baseName = cc.path.basename(assetName);
            const directory = cc.path.dirname(assetName);
            const skeletonPath = `${directory}/${baseName}_ske`;
            const texturePath = `${directory}/${baseName}_tex`;
            resLoader.loadRes(resourcePath, skeletonPath, dragonBones.DragonBonesAsset).then((skeletonAsset: dragonBones.DragonBonesAsset) => {
                if (skeletonAsset) {
                    ResourceUtil.assignResourceWith(skeletonAsset, targetNode.node);
                    resLoader.loadRes(resourcePath, texturePath, dragonBones.DragonBonesAtlasAsset).then((atlasAsset: dragonBones.DragonBonesAtlasAsset) => {
                        if (atlasAsset) {
                            targetNode.dragonAsset = skeletonAsset;
                            targetNode.dragonAtlasAsset = atlasAsset;
                            ResourceUtil.assignResourceWith(skeletonAsset, targetNode.node);
                            resolve(true);
                        } else {
                            reject(false);
                        }
                    });
                } else {
                    reject(false);
                }
            });
        });
    }

    /**
     * Adds touch event listeners to a node.
     * @param targetNode - The target node.
     * @param callback - The callback function to be executed on touch events.
     * @param context - The context in which the callback function is executed.
     * 建议方法名: addTouchEventListeners
     */
    static addTouchEventListener(targetNode: cc.Node, callback: Function, context: any): void {
        targetNode.on(cc.Node.EventType.TOUCH_START, callback, context);
        targetNode.on(cc.Node.EventType.TOUCH_MOVE, callback, context);
        targetNode.on(cc.Node.EventType.TOUCH_END, callback, context);
        targetNode.on(cc.Node.EventType.TOUCH_CANCEL, callback, context);
    }

    /**
     * Removes touch event listeners from a node.
     * @param targetNode - The target node.
     * 建议方法名: removeTouchEventListeners
     */
    static rmTouchEventListener(targetNode: cc.Node): void {
        targetNode.off(cc.Node.EventType.TOUCH_START);
        targetNode.off(cc.Node.EventType.TOUCH_MOVE);
        targetNode.off(cc.Node.EventType.TOUCH_END);
        targetNode.off(cc.Node.EventType.TOUCH_CANCEL);
    }

    /**
     * Applies a fade-out animation to a node.
     * @param targetNode - The target node.
     * @param duration - The duration of the fade-out animation.
     * @param removeAfter - Whether to remove the node from its parent after the animation (default is false).
     * @param cleanup - Whether to clean up the node after removal (default is true).
     * 建议方法名: applyFadeOutAnimation
     */
    static fadeOut(targetNode: cc.Node, duration: number, removeAfter: boolean = false, cleanup: boolean = true): void {
        cc.Tween.stopAllByTarget(targetNode);
        cc.tween(targetNode)
            .to(duration, { opacity: 0 })
            .call(() => {
                if (removeAfter) {
                    ResourceUtil.removeFromParentAndRelease(targetNode, cleanup);
                }
            })
            .start();
    }

    /**
     * Scales a node to fit within a given size.
     * @param targetNode - The target node.
     * @param targetSize - The target size.
     * 建议方法名: scaleNodeToFit
     */
    static scaleTo(targetNode: cc.Node, targetSize: number): void {
        const scaleFactor = targetSize / Math.max(targetNode.width, targetNode.height);
        targetNode.scale = scaleFactor;
    }
}

export default CommonUtils;